using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class Inventory : MonoBehaviour, ISaveManager
{
    #region 仓库
    // 单例模式实例
    public static Inventory instance;

    //起始物品列表
    public List<ItemData> startingEquipment;

    // 装备列表
    public List<InventoryItem> equipment;
    // 装备字典
    public Dictionary<ItemData_Equipment, InventoryItem> equipmentDictianory;

    // 物品列表/未装备的装备
    public List<InventoryItem> inventoryItems;
    // 物品字典
    public Dictionary<ItemData, InventoryItem> inventoryDictianory;

    // 储藏物品列表/材料
    public List<InventoryItem> stash;
    // 储藏物品字典
    public Dictionary<ItemData, InventoryItem> stashDictianory;

    [Header("物品栏 Inventory UI")]
    [SerializeField] private Transform inventorySlotParent; // 物品槽父节点
    [SerializeField] private Transform stashSlotParent; // 储藏槽父节点
    [SerializeField] private Transform equipmentSlotParent; // 装备槽父节点
    [SerializeField] private Transform statSlotParent;// 状态槽父节点

    // 从父节点获取
    private UI_ItemSlot[] inventoryItemSlot; // 物品槽数组
    private UI_ItemSlot[] stashItemSlot; // 储藏槽数组
    private UI_EquipmentSlot[] equipmentSlot;// 装备槽数组
    private UI_StatsSlot[] statSlot;// 状态槽数组

    private float lastTimeUseFlask;// 药水上一次使用的时间
    private float lastTimeUseArmor;// 盔甲上一次发动效果的时间

    public float flaskCoolDown { get; private set; }
    private float armorCoolDown;

    #endregion

    [Header("数据库")]
    public List<InventoryItem> loadedItems;
    public List<ItemData_Equipment> loadedEquipment;

    // 在对象创建时调用单例模式
    private void Awake()
    {
        // 如果实例为空，设置为当前实例
        if (instance == null)
            instance = this;
        else
            // 如果实例已存在，销毁当前对象
            Destroy(gameObject);
    }

    // 初始化
    void Start()
    {
        // 初始化物品列表
        inventoryItems = new List<InventoryItem>();
        // 初始化储藏物品列表
        stash = new List<InventoryItem>();
        // 初始化装备中列表
        equipment = new List<InventoryItem>();

        // 初始化物品字典
        inventoryDictianory = new Dictionary<ItemData, InventoryItem>();
        // 初始化储藏物品字典
        stashDictianory = new Dictionary<ItemData, InventoryItem>();
        // 初始化装备中字典
        equipmentDictianory = new Dictionary<ItemData_Equipment, InventoryItem>();

        // 获取所有子物品槽组件
        inventoryItemSlot = inventorySlotParent.GetComponentsInChildren<UI_ItemSlot>();
        // 获取所有子储藏槽组件
        stashItemSlot = stashSlotParent.GetComponentsInChildren<UI_ItemSlot>();
        // 获取所有子装备槽组件
        equipmentSlot = equipmentSlotParent.GetComponentsInChildren<UI_EquipmentSlot>();
        // 获取所有状态槽组件
        statSlot = statSlotParent.GetComponentsInChildren<UI_StatsSlot>();

        // 添加起始物品
        AddStartingItems();
    }

    #region 仓库相关

    // 起始物品
    private void AddStartingItems()
    {
        // 遍历 loadedEquipment 列表中的每一个装备物品
        foreach (ItemData_Equipment item in loadedEquipment)
        {
            // 装备物品
            EquipItem(item);
        }

        // 如果 loadedItems 列表中有物品
        if (loadedItems.Count > 0)
        {
            // 遍历 loadedItems 列表中的每一个物品
            foreach (InventoryItem item in loadedItems)
            {
                // 根据物品的堆叠大小添加物品
                for (int i = 0; i < item.stackSize; i++)
                {
                    AddItem(item.data);
                }
            }
            // 结束方法
            return;
        }

        // 如果 loadedItems 列表中没有物品，添加起始装备
        for (int i = 0; i < startingEquipment.Count; i++)
        {
            // 如果起始装备不为空，添加到物品列表中
            if (startingEquipment[i] != null)
                AddItem(startingEquipment[i]);
        }
    }

    // 更新物品槽UI
    public void UpdateSlotUI()
    {
        for (int i = 0; i < equipmentSlot.Length; i++)
        {
            equipmentSlot[i].CleanUpSlot();//死亡掉落清空装备槽
            // 遍历装备槽替换相应类型的装备UI
            foreach (KeyValuePair<ItemData_Equipment, InventoryItem> item in equipmentDictianory)
            {
                if (item.Key.equipmentType == equipmentSlot[i].slotType)
                {
                    equipmentSlot[i].UpdateSlot(item.Value);
                }
            }
        }

        for (int i = 0; i < inventoryItemSlot.Length; i++)
        {
            // 清除每个物品槽
            inventoryItemSlot[i].CleanUpSlot();
        }
        for (int i = 0; i < stashItemSlot.Length; i++)
        {
            // 清除每个储藏槽
            stashItemSlot[i].CleanUpSlot();
        }

        for (int i = 0; i < inventoryItems.Count; i++)
        {
            // 更新每个物品槽
            inventoryItemSlot[i].UpdateSlot(inventoryItems[i]);
        }
        for (int i = 0; i < stash.Count; i++)
        {
            // 更新每个储藏槽
            stashItemSlot[i].UpdateSlot(stash[i]);
        }

        UpdateStatsUI();

    }

    // 更新状态槽UI
    public void UpdateStatsUI()
    {
        for (int i = 0; i < statSlot.Length; i++)
        {
            // 更新状态插槽
            statSlot[i].UpdateStatValueUI();
        }
    }

    // 添加物品
    public void AddItem(ItemData _item)
    {
        // 根据物品类型添加到不同的列表
        if (_item.itemType == ItemType.Equipment && CanAddItem())
            AddToInventory(_item);
        else if (_item.itemType == ItemType.Material)
            AddToStash(_item);

        // 更新物品槽UI
        UpdateSlotUI();
    }

    // 添加物品到储藏
    private void AddToStash(ItemData _item)
    {
        // 如果物品已存在于储藏字典中，增加堆叠数量
        if (stashDictianory.TryGetValue(_item, out InventoryItem value))
        {
            value.AddStack();
        }
        else
        {
            // 如果物品不存在，创建新物品并添加到储藏列表和字典中
            InventoryItem newItem = new InventoryItem(_item);
            stash.Add(newItem);
            stashDictianory.Add(_item, newItem);
        }
    }

    // 添加物品到物品栏
    private void AddToInventory(ItemData _item)
    {
        // 如果物品已存在于字典中，增加堆叠数量
        if (inventoryDictianory.TryGetValue(_item, out InventoryItem value))
        {
            value.AddStack();
        }
        else
        {
            // 如果物品不存在，创建新物品并添加到列表和字典中
            InventoryItem newItem = new InventoryItem(_item);
            inventoryItems.Add(newItem);
            inventoryDictianory.Add(_item, newItem);
        }
    }

    // 移除物品
    public void RemoveItem(ItemData _item)
    {
        // 如果物品存在于字典中
        if (inventoryDictianory.TryGetValue(_item, out InventoryItem value))
        {
            // 如果堆叠数量小于等于1，移除物品
            if (value.stackSize <= 1)
            {
                inventoryItems.Remove(value);
                inventoryDictianory.Remove(_item);
            }
            else
            {
                // 否则减少堆叠数量
                value.RemoveStack();
            }
        }

        // 如果物品存在于储藏字典中
        if (stashDictianory.TryGetValue(_item, out InventoryItem stashvalue))
        {
            // 如果堆叠数量小于等于1，移除物品
            if (stashvalue.stackSize <= 1)
            {
                stash.Remove(stashvalue);
                stashDictianory.Remove(_item);
            }
            else
            {
                // 否则减少堆叠数量
                stashvalue.RemoveStack();
            }
        }

        // 更新物品槽UI
        UpdateSlotUI();
    }

    // 判断仓库是否满
    public bool CanAddItem()
    {
        if (inventoryItems.Count >= inventoryItemSlot.Length)
        {
            return false;
        }
        return true;
    }

    // 装备到装备槽
    public void EquipItem(ItemData _item)
    {
        // 将传入的物品转换为装备类型
        ItemData_Equipment newEquipment = _item as ItemData_Equipment;
        // 创建一个新的库存物品
        InventoryItem newItem = new InventoryItem(newEquipment);

        ItemData_Equipment oldEquipment = null;

        // 遍历装备字典，查找相同类型的旧装备
        foreach (KeyValuePair<ItemData_Equipment, InventoryItem> item in equipmentDictianory)
        {
            if (item.Key.equipmentType == newEquipment.equipmentType)
            {
                oldEquipment = item.Key;
            }
        }
        // 如果找到旧装备，则卸下旧装备并将其添加回物品栏
        if (oldEquipment != null)
        {
            UnequipItem(oldEquipment);
            AddItem(oldEquipment);
            //清除药水冷却
            if (oldEquipment.equipmentType == EquipmentType.Flask)
            {
                flaskCoolDown = 0;
            }
        }

        // 将新装备添加到装备列表和装备字典中
        equipment.Add(newItem);
        equipmentDictianory.Add(newEquipment, newItem);
        //改变角色属性
        newEquipment.AddModifiers();
        // 从物品栏中移除新装备
        RemoveItem(_item);
        // 更新UI
        UpdateSlotUI();
    }

    // 从装备列表移除旧装备
    public void UnequipItem(ItemData_Equipment oldEquipment)
    {
        // 尝试从装备字典中获取旧装备对应的库存物品
        if (equipmentDictianory.TryGetValue(oldEquipment, out InventoryItem value))
        {
            // 从装备列表和装备字典中移除旧装备
            equipment.Remove(value);
            equipmentDictianory.Remove(oldEquipment);
            //移除属性
            oldEquipment.RemoveModifiers();
        }
    }

    // 制造新装备
    public bool CanCraft(ItemData_Equipment _itemTocraft, List<InventoryItem> _requiredMaterials)
    {
        List<InventoryItem> materialsToRemove = new List<InventoryItem>(); // 要移除的材料列表
        for (int i = 0; i < _requiredMaterials.Count; i++)
        {
            // 检查库存中是否有所需材料
            if (stashDictianory.TryGetValue(_requiredMaterials[i].data, out InventoryItem stashValue))
            {
                // 检查库存中材料的数量是否足够
                if (stashValue.stackSize < _requiredMaterials[i].stackSize)
                {
                    Debug.Log("材料不足");
                    return false;
                }
                else
                {
                    materialsToRemove.Add(stashValue); // 添加到要移除的材料列表
                }
            }
            else
            {
                Debug.Log("没有该材料");
                return false;
            }
        }

        // 移除所需的材料
        for (int i = 0; i < materialsToRemove.Count; i++)
        {
            RemoveItem(materialsToRemove[i].data);
        }
        // 添加新制造的装备
        AddItem(_itemTocraft);
        Debug.Log("这是你的新装备：" + _itemTocraft.name);
        return true;
    }

    // 获取武器列表
    public List<InventoryItem> GetEquipmentList() => equipment;
    // 获取物品列表
    public List<InventoryItem> GetStashList() => stash;
    // 根据装备类型获取装备中的装备，可用于释放装备效果
    public ItemData_Equipment GetEquipment(EquipmentType _type)
    {
        ItemData_Equipment equipedItem = null;
        foreach (KeyValuePair<ItemData_Equipment, InventoryItem> item in equipmentDictianory)
        {
            if (item.Key.equipmentType == _type)
            {
                equipedItem = item.Key;
            }
        }
        return equipedItem;
    }

    // 使用药水的方法
    public void UseFlask()
    {
        // 获取当前装备的药水
        ItemData_Equipment currenFlask = GetEquipment(EquipmentType.Flask);
        // 如果没有装备药水，直接返回
        if (currenFlask == null) return;

        // 检查是否可以使用药水
        bool canUseFalsk = Time.time > lastTimeUseFlask + flaskCoolDown;
        if (canUseFalsk)
        {
            // 防止刚开始游戏不能使用道具效果
            flaskCoolDown = currenFlask.itemCooldown;
            // 执行药水效果
            currenFlask.ExecuteItemEffect(null);
            // 更新上次使用药水的时间
            lastTimeUseFlask = Time.time;
        }
        else
        {
            // 如果药水在冷却中，输出提示信息
            Debug.Log("药水冷却中");
        }
    }

    //判断能否使用盔甲效果
    public bool CanUseArmor()
    {
        ItemData_Equipment currenArmor = GetEquipment(EquipmentType.Armor);
        if (Time.time > lastTimeUseArmor + armorCoolDown)
        {
            // 防止刚开始游戏不能使用道具效果 ，armorCoolDown开始为零使用后才设置冷却
            armorCoolDown = currenArmor.itemCooldown;
            lastTimeUseArmor = Time.time;
            return true;
        }
        return false;
    }

    #endregion

    #region 保存数据相关
    // 从 GameData 中加载数据
    public void LoadData(GameData _data)
    {
        // 遍历 _data.inventory 中的每一个键值对
        foreach (KeyValuePair<string, int> pair in _data.inventory)
        {
            // 遍历物品数据库中的每一个物品
            foreach (var item in GetItemDataBase())
            {
                // 如果物品不为空且物品的 itemId 与键值对的键相同
                if (item != null && item.itemId == pair.Key)
                {
                    // 创建一个新的 InventoryItem 实例
                    InventoryItem itemToLoad = new InventoryItem(item);
                    // 设置物品的堆叠大小为键值对的值
                    itemToLoad.stackSize = pair.Value;

                    // 将物品添加到 loadedItems 列表中
                    loadedItems.Add(itemToLoad);
                }
            }
        }

        // 遍历 _data.equipmentId 中的每一个 itemId
        foreach (string itemId in _data.equipmentId)
        {
            // 遍历物品数据库中的每一个物品
            foreach (var item in GetItemDataBase())
            {
                // 如果装备不为空且物品的 itemId 与 itemId 相同
                if (item != null && item.itemId == itemId)
                {
                    // 将物品添加到 loadedEquipment 列表中，并将其转换为 ItemData_Equipment 类型
                    loadedEquipment.Add(item as ItemData_Equipment);
                }
            }
        }
    }

    // 保存数据到 GameData 中
    public void SaveData(ref GameData _data)
    {
        // 清空 _data.inventory
        _data.inventory.Clear();
        // 清空 _data.equipmentId
        _data.equipmentId.Clear();

        // 遍历 inventoryDictianory 中的每一个键值对
        foreach (KeyValuePair<ItemData, InventoryItem> pair in inventoryDictianory)
        {
            // 将键值对的键的 itemId 和值的堆叠大小添加到 _data.inventory 中
            _data.inventory.Add(pair.Key.itemId, pair.Value.stackSize);
        }

        // 遍历 stashDictianory 中的每一个键值对
        foreach (KeyValuePair<ItemData, InventoryItem> item in stashDictianory)
        {
            // 将键值对的键的 itemId 和值的堆叠大小添加到 _data.inventory 中
            _data.inventory.Add(item.Key.itemId, item.Value.stackSize);
        }

        // 遍历 equipmentDictianory 中的每一个键值对
        foreach (KeyValuePair<ItemData_Equipment, InventoryItem> pair in equipmentDictianory)
        {
            // 将键值对的键的 itemId 添加到 _data.equipmentId 中
            _data.equipmentId.Add(pair.Key.itemId);
        }
    }

    #endregion

    // 获取物品数据库
    private List<ItemData> GetItemDataBase()
    {
        // 创建一个新的 List<ItemData> 实例
        List<ItemData> itemDataBase = new List<ItemData>();
#if UNITY_EDITOR
        // 查找 "Assets/Data/Equipment" 目录下的所有资源
        string[] assetNames = AssetDatabase.FindAssets("", new[] { "Assets/Data/Items" });
        // 遍历每一个资源名称
        foreach (string SOName in assetNames)
        {
            // 获取资源的路径
            var SOpath = AssetDatabase.GUIDToAssetPath(SOName);
            // 加载资源并将其转换为 ItemData 类型
            var itemData = AssetDatabase.LoadAssetAtPath<ItemData>(SOpath);
            // 将资源添加到 itemDataBase 列表中
            itemDataBase.Add(itemData);
        }
#endif
        // 返回物品数据库
        return itemDataBase;
    }

}